 #include "sessionfriendarea.h"
#include <QScrollArea>
#include <QScrollBar>
#include <QVBoxLayout>
#include <QPushButton>
#include  <QLabel>
#include <QStyleOption>
#include <QPainter>
#include "mainwidget.h"
#include "model/data.h"
#include "debug.h"
#include "model/datacenter.h"

using namespace model;


SessionFriendArea::SessionFriendArea(QWidget *parent)
    : QScrollArea{parent} //C++11  {parent} 是一种初始化方式，使用花括号的语法表示初始化基类的构造函数。
{
    //1.设置必要属性
    //设置属性开启滚动 效果
    this->setWidgetResizable(true);
    //设置滚动条相关样式
    this->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 8px; background-color: rgb(243, 243 ,243); }");
    this->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { height: 0px ;} ");
    //去掉边框
    this->setStyleSheet("QWidget { border: none ;}");

    //2.创建widget
    container = new QWidget();
    //设置控件固定宽度
    container->setFixedWidth(260);
    //设置滚动区域的内容
    //滚动区域内容: container 将成为用户可以在滚动 区域中查看的内容。任何添加到 container 中的控件都将显示在 QScrollArea 内。
    //滚动条: 如果 container 的内容超出了 QScrollArea 的可见区域，Qt 会自动为 QScrollArea 添加滚动条，用户可以通过滚动条查看被截断的内容。
    this->setWidget(container);

    //3.给Widget 指定布局管理器,以便后添加其他元素
    QVBoxLayout* layout = new QVBoxLayout();
    //设置布局
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);



    //设置靠上对齐
    layout->setAlignment(Qt::AlignTop);
    container->setLayout(layout);

    //测试滚动效果
    // for (int i  = 0; i < 88; ++i)
    // {
    //     QPushButton * btn = new QPushButton();
    //     btn->setText("按钮");
    //     layout->addWidget(btn);
    // }

    //构造出临时数据进行界面调试依据.后续要删除掉

#if TEST_UI
    QIcon icon(":/resource/image/defaultAvatar.png");
    for (int i = 0; i < 33;  ++i)
    {
        this->addItem(SessionItemType, QString::number(i), icon,"誓约" + QString::number(i), "最后一条消息" + QString::number(i));
    }
#endif
}

void SessionFriendArea::clear()
{
    //layout下有 SessionFriendItem* item
    QLayout* layout = container->layout();
    //遍历布局管理器中所有元素，依次从布局管理器中删除掉
    //一边遍历一边删除，执行删除后元素下表发生变化,建议从后往前删除
    for (int i = layout->count() - 1; i >= 0;  --i)
    {
        //takeAt能移除对应下标的元素
        QLayoutItem* item = layout->takeAt(i);
        //还需要释放对象内存
        if (item->widget())
        {
            //释放移除内容的widget进行释放
            //正常的时候, new出来的添加到布局管理器里的
            delete item->widget();
        }
    }


}

//此时这个函数添加的不是SessionFriendItem,而是SessionFriendItem的子类
//SessionItem,FriendItem, ApplyItem其中一个
void SessionFriendArea::addItem(ItemType itemType, const QString& id,const QIcon &avatar,
                                const QString &name, const QString &text)
{
    SessionFriendItem* item = nullptr;
    if (itemType == SessionItemType)
    {
        item = new SessionItem(this, id, avatar, name, text);
    }
    else if (itemType == FriendItemType)
    {
        item = new FriendItem(this, id, avatar, name, text);
    }
    else if (itemType == ApplyItemType)
    {
        item = new ApplyItem(this, id, avatar, name);
    }
    else
    {
        LOG() << "错误的 ItemType! itemType=" << itemType;
    }
    //返回该窗口的布局管理器container->layout();
    container->layout()->addWidget(item);
}

void SessionFriendArea::clickItem(int index)
{
    if (index < 0 || index >=  container->layout()->count())
    {
        LOG() << "点击元素的下标超出范围! index=" <<index;
        return;
    }

    //获取布局项
    QLayoutItem* layoutItem = container->layout()->itemAt(index);
    if (layoutItem == nullptr  || layoutItem->widget() == nullptr)
    {
        LOG() << "指定元素不存在！ index= " << index;
        return;
    }
   SessionFriendItem* item =  dynamic_cast<SessionFriendItem*>(layoutItem->widget());
    item->select();


}

void SessionFriendItem::paintEvent(QPaintEvent *event)
{
    (void)event;
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}



////////////////////////////
/// 滚动区域 Item 的实现
///////////////////////////

SessionFriendItem::SessionFriendItem(QWidget *owner, const QIcon &avatar, const QString &name, const QString &text)
    :owner(owner)
{
    //设置高度和背景颜色
    this->setFixedHeight(70);
    this->setStyleSheet("QWidget  {  background-color: rgb(240, 240, 240) ;} ");

    //创建网格布局管理器
    QGridLayout * layout = new QGridLayout();
    layout->setContentsMargins(20, 0, 0, 0);

    //layout->setSpacing(0);
    //设置水平垂直距离
    layout->setHorizontalSpacing(10);
    layout->setVerticalSpacing(0);
    this->setLayout(layout);

    //创建头像
    QPushButton*  avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(50, 50);
    avatarBtn->setIconSize(QSize(50, 50));
    avatarBtn->setIcon(avatar);
    avatarBtn->setStyleSheet("QPushButton {border: none;}");
    //水平策略（第一个参数）: QSizePolicy::Expanding 表示控件在水平方向上可以扩展，允许它占据可用的额外空间。
    //垂直策略（第二个参数）: QSizePolicy::Fixed 表示控件在垂直方向上保持固定大小，不能改变高度。
    avatarBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    //创建名字
    QLabel* nameLabel = new QLabel();
    nameLabel ->setText(name);
    nameLabel->setStyleSheet("QLabel { font-size: 18px; font-weight: 600 ;}");
    nameLabel->setFixedHeight(35);
    nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

    //创建消息预览的  Label;
    messageLabel = new QLabel();
    messageLabel->setText(text);
    messageLabel->setFixedHeight(35);
    messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

    //头像处于0,0位置占据两行两列
    layout->addWidget(avatarBtn,0, 0, 2, 2);
    //添加名字,处于 0,2位置占据1行8列    为了接受和拒绝控件
    layout->addWidget(nameLabel, 0, 2, 1, 8);
    //添加消息,处于1, 2位置,占据1行8列   为了接受和拒绝控件
    layout->addWidget(messageLabel, 1, 2, 1, 8);
}

void SessionFriendItem::mousePressEvent(QMouseEvent *event)
{
    (void) event;
    select();
}

void SessionFriendItem::enterEvent(QEnterEvent *event)
{
    (void) event;
    //当前这个item被选中状态，背景则不受印象
    if (this->selected)
    {
        return;
    }
    //设置更深的颜色
    this->setStyleSheet("QWidget { background-color: rgb(215, 215, 215); }");
}

void SessionFriendItem::leaveEvent(QEvent *event)
{
    (void) event;
    //当前这个item被选中状态，背景则不受印象
    if (this->selected)
    {
        return;
    }
    //还原背景色
    this->setStyleSheet(" QWidget { background-color: rgb(240, 240, 240); }");
}

void SessionFriendItem::select()
{
    //鼠标点击时会触发这个函数

    //拿到layout下的所有item指针
    const QObjectList   children =  this-> parentWidget()->children();
    for (QObject* child : children )
    {
        if (!child->isWidgetType())
        {
            //判定是否为Widget
            continue;
        }
        //确实是Widget,把child强转成 SessionFriendItem
        //此处不仅设置ITEM背景色还要还原其他颜色背景色
        //选中点击时其他时还原以前选中的颜色
        SessionFriendItem* item = dynamic_cast<SessionFriendItem*>(child);
        if (item->selected == true)
        {
            item->selected = false;
            item->setStyleSheet(" QWidget { background-color: rgb(240, 240, 240);}");

        }
    }
    //点击时修改颜色
    this->setStyleSheet("QWidget { background-color: rgb(66,185,131);}");
    this->selected = true;
    this->active();

}

void SessionFriendItem::active()
{
    //父类的active
    //并不需要实现任何逻辑
}

////////////////////////////
/// 会话Item 的实现
///////////////////////////

SessionItem::SessionItem(QWidget *owner, const QString &chatSessionId,
                         const QIcon &avatar, const QString &name, const QString &lastMessage)
    :SessionFriendItem(owner, avatar, name, lastMessage)
    ,chatSessionId(chatSessionId)
    ,text(lastMessage)
{
    // 处理更新最后一个消息的信号
    DataCenter* dataCenter = DataCenter::getInstance();
    // 每个 SessionItem 构造的时候都会连接这个信号槽, 有30个item就连接了30个信号槽,但是只有ChatSessionId匹配的item才会真正更新界面
    // 的显示!!
    connect(dataCenter, &DataCenter::updateLastMessage, this, &SessionItem::updateLastMessage);

    //需要显示未读消息的数目， 为了支持客户端重启之后, 未读消息仍然能正确显示 ,
    int unread = dataCenter->getUnread(chatSessionId);
    if (unread > 0)
    {
        //存在未读消息

        this->messageLabel->setText( QString("[未读%1条]").arg(unread) + text);


    }

}

void SessionItem::active()
{
    //TODO点击之后, 要加载会话的历史消息列表
    LOG() << "点击SessionItem 触发的逻辑! chatSessionId=" << chatSessionId;

    // 加载会话历史消息,既会涉及到当前内存的数据操作,又会涉及到网络通信,还涉及到界面的变更
    MainWidget* mainWidget = MainWidget::getInStance();
    mainWidget->loadRecentMessage(chatSessionId);

    //清空未读消息数目更新显示
    DataCenter* dataCenter = DataCenter::getInstance();
    dataCenter->clearUnread(chatSessionId);

    //更新界面的显示, 把会话预览这里,前面的"[未读x条]" 内容干掉
    this->messageLabel->setText(text);



}

void SessionItem::updateLastMessage(const QString &chatSessionId)
{
    DataCenter* dataCenter = DataCenter::getInstance();
    // 1 先判定 信号中的会话id得和当前元素自身持有的 会话id 一致才真正处理
    if (this->chatSessionId != chatSessionId)
    {
        // 当前 sessionItem 不是正在发消息的SessionItem!
        return;
    }
    //chatSessionId 匹配才真正更新最后一条消息


    // 把最后一条消息获取到
    QList<Message>* messageList = dataCenter->getRecentMessageList(chatSessionId);
    if (messageList == nullptr || messageList->size()  == 0)
    {
        // 当前会话没有任何消息,无需更新
        return;
    }

    const Message& lastMessage = messageList->back();

    // 3 明确显示文本内容
    // 由于消息有四种类型
    // 文本消息,直接显示文本消息内容,图片消息显示[图片], 文件消息, 直接显示[文件]; 语言消息, 直接显示[语言];

    if (lastMessage.messageType == TEXT_TYPE)
    {
        text = lastMessage.content;

    }
    else if(lastMessage.messageType == IMAGE_TYPE)
    {
        text = "[图片]";
    }
    else if (lastMessage.messageType == FILE_TYPE)
    {
        text = "[文件]";
    }
    else if(lastMessage.messageType == SPEECH_TYPE)
    {
        text = "[语言]";
    }
    else
    {
        LOG() << "错误的消息类型";
        return;
    }


    // 4 把这个内容, 显示内容到界面上
    //后续还需要考虑到未读消息,还需要显示,关于未读消息的处理,后续编写"接受消息"的时候再处理
    // 先判定当前消息的会话是否正在选中的会话，如果是,不会更新任何未读消息
    //如果不是, 看未读消息是否大于0,做出拼装
    if (chatSessionId == dataCenter->getCurrentChatSessionId())
    {
        this->messageLabel->setText(text);
    } else {
        int unread = dataCenter->getUnread(chatSessionId);
        if (unread > 0) {
            this->messageLabel->setText(QString("[未读%1条]").arg(unread) + text);
        }
    }


}




////////////////////////////
/// 好友Item 的实现
///////////////////////////

FriendItem::FriendItem(QWidget *owner, const QString &userId, const QIcon &avatar,
                       const QString &name, const QString &description)
    :SessionFriendItem(owner, avatar, name, description)
    ,userId(userId)
{

}

void FriendItem::active()
{
    //TODO点击之后激活对应的会话列表元素
    LOG() << "点击 FriendItem 触发的逻辑! userId=" << userId;

    MainWidget* mainWidget = MainWidget::getInStance();
    mainWidget->switchSession(userId);

}


////////////////////////////
/// 好友申请Item 的实现
///////////////////////////

ApplyItem::ApplyItem(QWidget *owner, const QString &userId, const QIcon &avatar, const QString &name)
    :SessionFriendItem(owner, avatar, name, " ")
    ,userId(userId)
{
    //1.移除父类的MessageLabel
    QGridLayout* layout = dynamic_cast<QGridLayout*>(this->layout());
    layout->removeWidget(messageLabel);
    //释放内存
    delete messageLabel;

    //2.创建两个按钮
    QPushButton* acceptBtn = new QPushButton();
    acceptBtn->setText("同意");
    QPushButton* rejectBtn = new QPushButton();
    rejectBtn->setText("拒绝");

    //3.添加到布局管理器
    layout->addWidget(acceptBtn, 1, 2, 1, 1);
    layout->addWidget(rejectBtn, 1, 3, 1, 1);

    // 4.添加信号槽
    connect(acceptBtn, &QPushButton::clicked, this, &ApplyItem::acceptFriendApply);
    connect(rejectBtn, &QPushButton::clicked, this, &ApplyItem::rejectFriendApply);
}

void ApplyItem::active()
{
     //TODO 这个函数不需要实现,点击之后无事发生
    LOG() << "点击ApplyItem 触发的逻辑! userId= " << userId;
}

void ApplyItem::acceptFriendApply()
{
    // 发送网络请求告知服务器,同意了
    DataCenter* dataCenter = DataCenter::getInstance();
    //同意谁的好友申请
    //针对这个操作,信号处理,是需要更新好友列表以及好友申请列表,直接在主窗口处理更合适
    dataCenter->acceptFriendApplyAsync(this->userId);

}

void ApplyItem::rejectFriendApply()
{
    DataCenter* dataCenter = DataCenter::getInstance();
    dataCenter->rejectFriendApplyAsync(this->userId);
}
